/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package shaman.storage.common;

import java.util.Date;
import java.util.Map;

/**
 *
 * @author dmitriy
 */
public class FileProperties implements FilePropertiesAccessor {

    public static final String PROPERTIES_PREFIX="common::";
    public static final String PROPERTY_FILENAME=PROPERTIES_PREFIX+"filename";
    public static final String PROPERTY_LENGTH=PROPERTIES_PREFIX+"length";
    public static final String PROPERTY_HASH=PROPERTIES_PREFIX+"hash";
    public static final String PROPERTY_DATE=PROPERTIES_PREFIX+"date";

    private final FilePropertiesAccessor acc;
    private String fileName;
    
    /**
     * Создаёт объект свойств с единственным заданным свойством - именем файла
     * @param fileName Имя файла
     */
    public FileProperties(String fileName) {
        acc=new FilePropertiesStorage(true);
        setFileName(fileName);
    }

    /**
     * Создаёт объект свойств с заданным именем файла и другими свойствами
     * @param fileName Имя файла
     * @param properties другие свойства
     */
    public FileProperties(String fileName, Map<String, String> properties) {
        acc=new FilePropertiesStorage(true);
        setFileName(fileName);
        if (properties!=null)
        {
            for (Map.Entry<String, String> entry: properties.entrySet())
            {
                acc.setProperty(entry.getKey(), entry.getValue());
            }
        }
    }

    public FileProperties(FilePropertiesAccessor acc) {
        this.acc = acc;
    }

    /**
     * Возвращает имя файла
     * @return
     */
    public synchronized String getFileName() {
        if (fileName==null)
            fileName=acc.getProperty(FileProperties.PROPERTY_FILENAME);
        return fileName;
    }

    /**
     * Устанавливает имя файла. Доступно, только если имя файла ещё не установлено
     */
    public synchronized void setFileName(String filename) {
        if (getFileName() != null) {
            throw new IllegalStateException("Cannot change file name");
        } else {
            this.fileName = filename;
        }
        acc.setProperty(PROPERTY_FILENAME, fileName);
    }
    /**
     * Возвращает размер файла
     * @return
     */
    public long getLength()
    {
        long len=0;
        String lenProp=acc.getProperty(PROPERTY_LENGTH);
        try {
            if (lenProp!=null)
                len=Long.parseLong(lenProp);
        } catch (NumberFormatException ex) {
        }
        return len;
    }

    /**
     * Устанавливает длину файла
     * @param newLength
     */
    public void setLength(long newLength)
    {
        acc.setProperty(PROPERTY_LENGTH, String.valueOf(newLength));
    }

    /**
     * Получает MD5-отпечаток файла
     * @return
     */
    public byte[] getHash()
    {
        String hashProp=acc.getProperty(PROPERTY_HASH);
        if (hashProp==null || hashProp.length()<2)
            return null;
        int byteLength=hashProp.length()/2;
        byte[] ret=new byte[byteLength];
        int i;
        for (i=0; i<byteLength; i++)
        {
            String part=hashProp.substring(i*2, i*2+2);
            int number;
            try {
                number=Integer.parseInt(part, 16);
            } catch (NumberFormatException ex) {
                return null;
            }
            ret[i]=(byte) number;
        }
        return ret;
    }

    /**
     * Получает MD5-отпечаток как строку
     * @return
     */
    public String getHashString()
    {
        return acc.getProperty(PROPERTY_HASH);
    }

    /**
     * Устанавливает отпечаток файла
     * @param hash
     */
    public void setHash(byte[] hash)
    {
        StringBuilder buff=new StringBuilder();
        for (byte b: hash)
        {
            String byteString=Integer.toHexString(b);
            byteString=byteString.substring(Math.max(0, byteString.length()-2));
            if (byteString.length()==1)
                buff.append("0");
            buff.append(byteString);
        }
        acc.setProperty(PROPERTY_HASH, buff.toString());
    }

    /**
     * Получает дату последнего изменения файла
     * @return
     */
    public Date getDate()
    {
        String dateString=acc.getProperty(PROPERTY_DATE);
        if (dateString==null)
            return null;
        long dateNumber;
        try {
            dateNumber=Long.parseLong(dateString);
        } catch (NumberFormatException ex) {
            return null;
        }
        return new Date(dateNumber);
    }

    /**
     * Устанавливает дату последнего изменения файла
     * @param newDate дата последнего изменения
     */
    public void setDate(Date newDate) {
        acc.setProperty(PROPERTY_DATE, String.valueOf(newDate.getTime()));
    }

    public Map<String, String> getProperties() {
        return acc.getProperties();
    }

    public String getProperty(String name) {
        return acc.getProperty(name);
    }

    public boolean isImmutable() {
        return acc.isImmutable();
    }

    public void setImmutable() {
        acc.setImmutable();
    }

    public void setProperty(String name, String value) {
        acc.setProperty(name, value);
    }

}
